/*
 * R/C receiver input monitoring for Flying Fox
 *
 * by Zik Saleeba 2008-03-05
 */

#include "ffox.h"
#include "board.h"
#include "servo.h"
#include "receiver.h"

/* the number of timer peripherals we're using for receiver input */
#define NUM_TIMER_UNITS 3

/* module variables */
static volatile unsigned int ReceiverSignal[NUM_RECEIVER_INPUTS];
static volatile unsigned int ReceiverPos[NUM_RECEIVER_INPUTS];

/* the list of timer peripherals we're using */
static TIM_TypeDef *ReceiverTimerUnit[NUM_TIMER_UNITS] = { TIM1, TIM3, TIM5 };

struct ReceiverInfoStruct
{
    TIM_TypeDef *TIMPort;
    uint16_t TIMChannel;
    
    GPIO_TypeDef *GPIOPort;
    uint16_t GPIOPin;
};

static struct ReceiverInfoStruct ReceiverInfo[NUM_RECEIVER_INPUTS] = 
{ 
    { RECEIVER1_TIM_PORT, RECEIVER1_CH, RECEIVER1_GPIO_PORT, RECEIVER1_PIN },
    { RECEIVER2_TIM_PORT, RECEIVER2_CH, RECEIVER2_GPIO_PORT, RECEIVER2_PIN },
    { RECEIVER3_TIM_PORT, RECEIVER3_CH, RECEIVER3_GPIO_PORT, RECEIVER3_PIN },
    { RECEIVER4_TIM_PORT, RECEIVER4_CH, RECEIVER4_GPIO_PORT, RECEIVER4_PIN },
    { RECEIVER5_TIM_PORT, RECEIVER5_CH, RECEIVER5_GPIO_PORT, RECEIVER5_PIN },
    { RECEIVER6_TIM_PORT, RECEIVER6_CH, RECEIVER6_GPIO_PORT, RECEIVER6_PIN },
    { RECEIVER7_TIM_PORT, RECEIVER7_CH, RECEIVER7_GPIO_PORT, RECEIVER7_PIN },
    { RECEIVER8_TIM_PORT, RECEIVER8_CH, RECEIVER8_GPIO_PORT, RECEIVER8_PIN }
};    


/*
 * NAME:        Receiver_Init
 * ACTION:      Initialise the receiver subsystem.
 */
 
void Receiver_Init( void )
{
    int Count;
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_ICInitTypeDef  TIM_ICInitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
   
    /* set up the initial positions for each channel */
    for (Count = 0; Count < NUM_RECEIVER_INPUTS; Count++)
        ReceiverPos[Count] = SERVO_MID_US;
    
    /* TIM1, TIM3 and TIM5 clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);

    /* GPIO Configuration: configure receiver pins as inputs with a pull-down resistor */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    for (Count = 0; Count < NUM_RECEIVER_INPUTS; Count++)
    {
        GPIO_InitStructure.GPIO_Pin = ReceiverInfo[Count].GPIOPin;
        GPIO_Init(ReceiverInfo[Count].GPIOPort, &GPIO_InitStructure);
    }
    
    /* configure PWM input mode */
    for (Count = 0; Count < NUM_RECEIVER_INPUTS; Count++)
    {
        /* TIMx configuration: PWM Input mode ------------------------
         The external signal is connected to TIMx CHy pin, 
         The Rising edge is used as active edge,
         The TIMx CCR2 is used to compute the frequency value 
         The TIMx CCR1 is used to compute the duty cycle value
        ------------------------------------------------------------ */
        TIM_ICStructInit(&TIM_ICInitStructure);
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
        TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
        TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
        TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        TIM_ICInitStructure.TIM_ICFilter = 0x0;
        
        TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
    }
    
    for (Count = 0; Count < NUM_TIMER_UNITS; Count++)
    {
        /* Select the TIM3 Input Trigger: TI2FP2 */
        TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);
        
        /* Select the slave Mode: Reset Mode */
        TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
        
        /* Enable the Master/Slave Mode */
        TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
        
        /* TIM enable counter */
        TIM_Cmd(TIM3, ENABLE);
        
        /* Enable the CC2 Interrupt Request */
        TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
    }
    
    /* enable the TIM1, TIM3 and TIM5 global interrupts */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannel = TIM1_IRQn;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    NVIC_Init(&NVIC_InitStructure);
}


/*
 * NAME:        Receiver_Get
 * ACTION:      Get the current position of a R/C receiver input
 * PARAMETERS:  int Port - which receiver input to get (0-6)
 *              int *Signal - set to TRUE if a signal is available, FALSE otherwise
 * RETURNS:     int - the current receiver input position.
 */
 
int Receiver_Get(int Port, int *Signal)
{
    if (Port >= 0 && Port < NUM_RECEIVER_INPUTS)
    {
        *Signal = ReceiverSignal[Port];
        return ReceiverPos[Port];
    }
    else
    {
        *Signal = FALSE;
        return 0;
    }
}
